package cn.lingyangwl.framework.data.mate.fieldbind;

import cn.hutool.core.collection.CollUtil;
import cn.lingyangwl.framework.data.mate.fieldbind.inter.IDataBind;
import cn.lingyangwl.framework.data.mate.fieldbind.inter.IFieldBindAnnotationDataGetter;
import cn.lingyangwl.framework.data.mate.fieldbind.model.AnnotationMetadata;
import cn.lingyangwl.framework.data.mate.fieldbind.model.FieldDefine;
import cn.lingyangwl.framework.tool.core.StringUtils;
import cn.lingyangwl.framework.tool.core.reflection.MetaObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 字段值管理器
 *
 * @author shenguangyang
 */
@Slf4j
@Component
public class FieldValueManager {
    @Resource
    private Map<String, SetTargetFieldValueHandler<?>> setTargetFieldValueHandlerBean;

    @Resource
    private Map<String, GetSourceFieldValueHandler<?>> getSourceFieldValueHandlerBean;

    /**
     * key: 目标字段类型, eg: java.util.List<java.lang.String>, java.lang.String
     */
    private final Map<String, SetTargetFieldValueHandler<?>> setTargetFieldValueHandlerMap = new HashMap<>();
    private final Map<String, GetSourceFieldValueHandler<?>> getSourceFieldValueHandlerMap = new HashMap<>();

    @PostConstruct
    public void init() {
        setTargetFieldValueHandlerBean.forEach((k, v) -> {
            Type type = getType(v);
            setTargetFieldValueHandlerMap.put(type.getTypeName(), v);
        });

        getSourceFieldValueHandlerBean.forEach((k, v) -> {
            Type type = getType(v);
            getSourceFieldValueHandlerMap.put(type.getTypeName(), v);
        });
    }

    private Type getType(Object obj) {
        Type[] types = obj.getClass().getGenericInterfaces();
        ParameterizedType parameterizedType = (ParameterizedType) types[0];
        return parameterizedType.getActualTypeArguments()[0];
    }

    /**
     * 设置元数据对象<br>
     * 每个对象的属性都会调用一次, 比如需要处理一个对象, 其中有10个字段需要进行字段绑定操作, 那么就会被调用10次
     *
     * @param metaObject     处理的对象元数据
     * @param valuesOfTypes   对象中所有字典type对应的字典code数据集, 来自 {@link IDataBind#getCodesOfTypes(List)}} 返回结果
     * @param fieldValue     注解所在字段的值
     * @param fieldDefine 字段定义数据, 可以获取当前处理的字段上自定义的字段绑定注解数据, 来自
     *                       {@link IFieldBindAnnotationDataGetter#initFieldBindAnnotation(Annotation)} (Annotation)} ()}
     *                       方法的返回值
     */
    public <T> void setTargetValue(MetaObject metaObject, T valuesOfTypes, IDataBind<T> dataBind,
                            Object fieldValue, FieldDefine fieldDefine) {
        AnnotationMetadata annot = fieldDefine.getAnnotationMetadata();
        String delimiter = annot.getDelimiter();
        String annoTargetDelimiter = annot.getTargetDelimiter();
        String targetDelimiter = StringUtils.isEmpty(annoTargetDelimiter) ? delimiter : annoTargetDelimiter;
        String valueFieldTypeName = fieldDefine.getTargetField().getGenericType().getTypeName();
        String codeFieldTypeName = fieldDefine.getField().getGenericType().getTypeName();
        SetTargetFieldValueHandler<?> setTargetFieldValueHandler = setTargetFieldValueHandlerMap.get(valueFieldTypeName);
        GetSourceFieldValueHandler<?> getSourceFieldValueHandler = getSourceFieldValueHandlerMap.get(codeFieldTypeName);
        if (Objects.isNull(setTargetFieldValueHandler)) {
            log.warn("字典翻译 ===> 目标字段 [{}] 类型为 [{}] 暂时不支持", fieldDefine.getTargetField().getName(), valueFieldTypeName);
            return;
        }

        if (Objects.isNull(getSourceFieldValueHandler)) {
            log.warn("字典翻译 ===> 注解所在字段 [{}] 类型为 [{}] 暂时不支持", fieldDefine.getField().getName(), codeFieldTypeName);
            return;
        }

        Collection<Object> valueList = new ArrayList<>();

        List<?> codeList = getSourceFieldValueHandler.getValue(fieldValue, fieldDefine);

        for (int i = 0; i < codeList.size(); i++) {
            Object code = codeList.get(i);
            if (Objects.isNull(code)) {
                continue;
            }

            // 如果code的默认值不为空, 且映射字段不为空就将映射字段的值赋值给目标字段
            if (StringUtils.isNotEmpty(annot.getCodeDefault())) {
                if (String.valueOf(code).equals(annot.getCodeDefault()) && StringUtils.isNotEmpty(annot.getMapperTarget())) {
                    Object mapperTargetValue = metaObject.getValue(annot.getMapperTarget());
                    if (Objects.nonNull(mapperTargetValue)) {
                        valueList.add(mapperTargetValue);
                    }
                    continue;
                }
            }

            // 获取字段值, 并判断字段编码是否存在
            Object value = dataBind.getCodeValue(valuesOfTypes, annot.getType(), String.valueOf(code));
            value = Objects.isNull(value) && annot.getTargetEqCode() ? code : value;
            if (Objects.nonNull(value)) {
                valueList.add(value);
            }

            // 如果分隔符不为空, 且目标字段为字符串类型才生效
            if (Objects.nonNull(value) && (i < codeList.size() - 1) && StringUtils.isNotEmpty(targetDelimiter)
                && ( setTargetFieldValueHandler instanceof SetTargetFieldValueHandler.StringType))  {
                valueList.add(targetDelimiter);
            }
        }

        if (CollUtil.isEmpty(valueList)) {
            return;
        }
        setTargetFieldValueHandler.setValue(valueList, codeList, metaObject, fieldDefine);
    }

}
